package weiyao.xinxidasai.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.lang.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import weiyao.xinxidasai.DTO.Result;
import weiyao.xinxidasai.Utils.Encryption.ARGON2.ARGON2IDUtils;



import weiyao.xinxidasai.Utils.Encryption.SM4utils.Sm4Util;
import weiyao.xinxidasai.Utils.FaceToken.FaceRegistry;
import weiyao.xinxidasai.Utils.ThreadLocal.UserHolder;
import weiyao.xinxidasai.config.Redis.RedisCache;
import weiyao.xinxidasai.mapper.FolderMapper;
import weiyao.xinxidasai.mapper.UserMapper;
import weiyao.xinxidasai.pojo.FilesFolder;
import weiyao.xinxidasai.pojo.Users;
import weiyao.xinxidasai.service.FolderService;
import weiyao.xinxidasai.service.UserService;

import javax.annotation.Resource;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import static weiyao.xinxidasai.Utils.FaceToken.FaceDetection.validateFaceDetection;
import static weiyao.xinxidasai.Utils.UtilsKey.RedisConstants.LOGIN_USER_KEY;
import static weiyao.xinxidasai.Utils.UtilsKey.RedisConstants.LOGIN_USER_TTL;

@Service
public class UserServiceImpl implements UserService {

    private final StringRedisTemplate stringRedisTemplate;
    @Autowired
    private FolderMapper folderMapper;
    @Autowired
    private RedisCache redisCache;
    public UserServiceImpl(StringRedisTemplate stringRedisTemplate) {
        this.stringRedisTemplate = stringRedisTemplate;
    }

    @Resource
    private FolderService folderService;
    @Resource
    private UserMapper usermapper;

    @Override
    public int addUser(Users user) {
        //注册层 加密
        user.setPassword(ARGON2IDUtils.encryptWithArgon2(user.getPassword(),2));
        return usermapper.insertUser(user);

    }

    @Override
    public int countByUsername(String username) {
        return usermapper.countByUsername(username);
    }


    @Override
    public Result login(Users user) {

        int count = usermapper.countByUsername(user.getUsername());
        if (count > 1 || count < 0) return Result.fail("数据库异常");
        if (count == 0) return Result.fail("用户名或者密码错误");
        Users userDTO = usermapper.findByUsername(user.getUsername());

        // 修复1：使用从数据库获取的用户ID，而不是UserHolder中的（此时尚未登录）
        String userId = String.valueOf(userDTO.getUserId());

        // 修复2：先检查缓存键是否存在，再获取值
        String lockKey = userId + "lock";

        // 修复3：安全地获取缓存值并进行空值检查
        Object lockValue = redisCache.getCache(lockKey);
        if (lockValue != null) {
            // 修复4：确保值是Boolean类型
            if (lockValue instanceof Boolean && (Boolean) lockValue) {
                return Result.fail("抱歉该用户暂时被锁定1小时，无法登录");
            }
            // 如果是其他类型（如String），也视为锁定状态
            else if (lockValue.toString().equalsIgnoreCase("true")) {
                return Result.fail("抱歉该用户暂时被锁定1小时，无法登录");
            }
        }
        String inputPassword = user.getPassword();
        boolean passwordValid = false;

        // 场景1:没有密钥的用户(使用ARGON2ID验证)
        if (userDTO.getSecretKey() == null) {
           //使用基本加密验证
            passwordValid = ARGON2IDUtils.verifyPassword(userDTO.getPassword(),inputPassword,null,false);
            if (passwordValid) {
                // 创建根目录(修正逻辑)
                List<FilesFolder> folders = folderMapper.selectFoldersByUserId(userDTO.getUserId());
                // 生成token和存储Redis的逻辑
                String token = UUID.randomUUID().toString(true);
                Map<String, Object> userMap = BeanUtil.beanToMap(
                        userDTO,
                        new HashMap<>(),
                        CopyOptions.create()
                                .setIgnoreNullValue(true)
                                .setIgnoreProperties("password", "secretKey")
                                .setFieldValueEditor((fieldName, fieldValue) ->
                                        fieldValue != null ? fieldValue.toString() : null
                                )
                );
                String tokenkey = LOGIN_USER_KEY + token;
                stringRedisTemplate.opsForHash().putAll(tokenkey, userMap);
                stringRedisTemplate.expire(tokenkey, LOGIN_USER_TTL, TimeUnit.MINUTES);

                if (folders == null || folders.isEmpty()) { // 同时处理null和空列表
                    System.out.println("创了一个根目录");
                    createFolder(userDTO.getUserId(), "");
                }

                return Result.ok(token);
            }else {return Result.fail("密码错误");}
        }
        // 场景2:有密钥的用户
        else {
            // 使用基本加密验证密码
            if (ARGON2IDUtils.verifyPassword(userDTO.getPassword(),inputPassword,null,false)) {
                // 密码尚未使用SM4加密，对密码进行SM4加密并更新数据库
                String encryptedPassword = Sm4Util.encrypt(userDTO.getPassword(), userDTO.getSecretKey());
                usermapper.updatepass(encryptedPassword, userDTO.getUserId());

                // 创建根目录(修正逻辑)
                List<FilesFolder> folders = folderMapper.selectFoldersByUserId(userDTO.getUserId());


                // 生成token和存储Redis的逻辑
                String token = UUID.randomUUID().toString(true);
                Map<String, Object> userMap = BeanUtil.beanToMap(
                        userDTO,
                        new HashMap<>(),
                        CopyOptions.create()
                                .setIgnoreNullValue(true)
                                .setIgnoreProperties("password", "secretKey")
                                .setFieldValueEditor((fieldName, fieldValue) ->
                                        fieldValue != null? fieldValue.toString() : null
                                )
                );
                String tokenkey = LOGIN_USER_KEY + token;
                stringRedisTemplate.opsForHash().putAll(tokenkey, userMap);
                stringRedisTemplate.expire(tokenkey, LOGIN_USER_TTL, TimeUnit.MINUTES);
                if (folders == null || folders.isEmpty()) { // 同时处理null和空列表
                    System.out.println("创了一个根目录");
                    createFolder(userDTO.getUserId(),"");
                }
                return Result.ok(token);
            } else {
                // 密码已经使用SM4加密，使用SM4解密输入的密码并与数据库中的密码进行验证

                passwordValid = ARGON2IDUtils.verifyPassword(userDTO.getPassword(),inputPassword,userDTO.getSecretKey(),true);
                if (passwordValid) {
                    UserHolder.saveUser(userDTO);
                    System.out.println("aaa"+folderMapper.selectFoldersByUserId(userDTO.getUserId()));


                    // 生成token和存储Redis的逻辑
                    String token = UUID.randomUUID().toString(true);
                    Map<String, Object> userMap = BeanUtil.beanToMap(
                            userDTO,
                            new HashMap<>(),
                            CopyOptions.create()
                                    .setIgnoreNullValue(true)
                                    .setIgnoreProperties("password", "secretKey")
                                    .setFieldValueEditor((fieldName, fieldValue) ->
                                            fieldValue != null? fieldValue.toString() : null
                                    )
                    );

                    String tokenkey = LOGIN_USER_KEY + token;
                    stringRedisTemplate.opsForHash().putAll(tokenkey, userMap);
                    stringRedisTemplate.expire(tokenkey, LOGIN_USER_TTL, TimeUnit.MINUTES);
                    // 创建根目录(修正逻辑)
                    List<FilesFolder> folders = folderMapper.selectFoldersByUserId(userDTO.getUserId());
                    if (folders == null || folders.isEmpty()) { // 同时处理null和空列表
                        System.out.println("创了一个根目录");
                        createFolder(userDTO.getUserId(),"");
                    }
                    return Result.ok(token);
                }

                return Result.fail("用户名或密码错误");
            }
        }
    }



    @Override
    public Result FaceToken(MultipartFile file) throws IOException {
        // 获取当前用户
        Long userId = UserHolder.getUser().getUserId();
        Users user = usermapper.findByUserId(userId);
        if (user.getSecretKey() != null&&!(user.getSecretKey().isEmpty())) {
            return Result.fail("已经有密钥，请不要重复检测");

        }


        // 检查Redis锁定状态
        String redisKey = "facetoken:" + userId;
        String countStr = stringRedisTemplate.opsForValue().get(redisKey);
        Integer failureCount = countStr != null ? Integer.valueOf(countStr) : 0;

        if (failureCount != null && failureCount >= 5) {
            Map<String, Object> result = new HashMap<>();
            result.put("error", "人脸认证功能已被锁定，请30分钟后再试");
            return Result.ok(result);
        }
        // 空文件检查
        if (file == null || file.isEmpty()) {
            Map<String, Object> result = new HashMap<>();
            result.put("error", "请选择上传文件");
            return Result.ok(result);
        }

        // 将MultipartFile转换为File
        File tempFile = File.createTempFile("face_", ".tmp");
        file.transferTo(tempFile);

        // 调用人脸检测方法
        Map<String, Object> result = validateFaceDetection(tempFile);

        // 删除临时文件
        tempFile.delete();

        // 获取计数器结果
        int successCount = (int) result.get("success_count");

        // 处理token
        if (successCount < 10) {
            // 认证失败，移除token
            result.remove("face_token");
            result.put("face_token", "抱歉您的人脸认证未通过，请根据左侧未通过的信息拍取正确的信息");
            stringRedisTemplate.opsForValue().increment(redisKey);
            stringRedisTemplate.expire(redisKey, 30, TimeUnit.MINUTES);
        } else {
            // 认证成功，处理token并存入数据库
            String faceToken = (String) result.get("face_token");

            boolean registerSuccess = FaceRegistry.registerFace(
                    String.valueOf(userId),  // 百度API要求字符串类型的用户ID
                    faceToken
            );
            // 设置token前后10位为*号
            if (faceToken != null && faceToken.length() > 20) {
                String maskedToken = "**********" + faceToken.substring(10, faceToken.length()-10) + "**********";
                result.put("face_token", maskedToken);
            }

            // 存入数据库
            user.setSecretKey(faceToken);
            usermapper.updateFaceToken(user);
            stringRedisTemplate.delete(redisKey);
        }

        return Result.ok(result);
    }



    public Result createFolder(Long userId,String Path) {
        //判断是否有该文件夹
        FilesFolder filesFolder = folderMapper.selectByPathanduser(userId, Path);
        if (filesFolder != null) {
            return Result.fail("文件夹已经被创建 ");
        }

        // 2. 创建文件夹记录
        FilesFolder folder = new FilesFolder();
        folder.setUserId(userId);
        folder.setFolderPath(Path);

        folderMapper.insertFolder(folder);
        return Result.ok();
    }
}
